package cate.game.play.fighter;

import cate.common.table.d.GDSkill;
import cate.common.table.fight.skill.row.SkillBaseRow;
import cate.common.table.fight.skill.row.SkillEnhanceRow;
import cate.common.util.XT;
import cate.game.attr.FightAttr;
import cate.game.play.config.AllPlayCfg;
import cate.game.play.config.enhance.SkillEnhanceCfg;
import cate.game.play.config.skill.SkillCfg;
import cate.game.play.proce.action.ctx.ActionCtx;
import cate.game.play.proce.play.PlayCtx;
import cate.game.play.skill.Skill;
import cate.game.play.skill.passive.PassiveHandler;
import cate.game.play.skill.passive.hero.英雄觉醒PH;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.util.collection.ListKit;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@NoteClass("战斗者的技能")
public class FightSkills {

	@NoteField("战斗者")
	@JsonIgnore
	@Transient
	private transient Fighter owner;

	@NoteField(value = "技能id", detail = "包括自身的技能以及场景添加的技能")
	private Set<Integer> skillTids = new HashSet<>();

	@NoteField("全部技能")
	@JsonIgnore
	@Transient
	private Set<Skill> allSkill;

	@NoteField("主动技能")
	@JsonIgnore
	@Transient
	private Set<Skill> active = new HashSet<>();

	@NoteField("被动技能")
	@JsonIgnore
	@Transient
	private Set<Skill> passive = new HashSet<>();

	@NoteField(value = "pvp技能", detail = "战斗开始时根据是否是pvp添加")
	@JsonIgnore
	@Transient
	private Set<Integer> pvpSkills = new HashSet<>();



	public void init(Fighter owner){
		this.owner = owner;
	}

	/**
	 * 获取所有技能
	 * @return
	 */
	public Set<Skill> getAllSkill() {
		if (allSkill == null) {
			allSkill = new HashSet<>();
			allSkill.addAll(active);
			allSkill.addAll(passive);
		}
		return allSkill;
	}

	/**
	 * 获取所有主动技能（包括变身前和变身后的技能）
	 * @return
	 */
	public Set<Skill> getAllActive(){
		return new HashSet<>(active);
	}

	/**
	 * 获取普攻
	 * @return
	 */
	public Skill getAttack() {
		for (Skill skill : getAllActive()) {
			if (skill.cfg.row.type == GDSkill.Type.ATTACK) {
				return skill;
			}
		}
		return null;
	}

	public Set<Integer> getSkillTids(){
		return skillTids;
	}

	//添加技能
	public void addSkills(List<Integer> skills) {
		if (XT.isBlank(skills)) {
			return;
		}
		this.skillTids.addAll(skills);
	}

	//添加pvp技能
	public void addPvPSkills(List<Integer> skills){
		if (XT.isBlank(skills)) {
			return;
		}
		this.pvpSkills.addAll(skills);
	}

	/**
	 * 实例化技能（需要等所有技能加入后才可以实例）
	 * @param playCtx
	 */
	public void beforeFight(PlayCtx playCtx) {
		AllPlayCfg config = playCtx.config;
		if (playCtx.isPvP() && !pvpSkills.isEmpty()) {
			skillTids.addAll(pvpSkills);
			pvpSkills.clear();
		}
		skillTids = filterSkill(config, skillTids);
		List<SkillCfg> allSkrList = new ArrayList<>();
		for (Integer skill : skillTids) {
			SkillCfg skillCfg = config.skill.get(skill);
			if (skillCfg != null) {
				allSkrList.add(skillCfg);
				//被动属性
				if (StringUtils.isNotBlank(skillCfg.row.fightAttrStr)) {
					this.owner.attr.addAttr(new FightAttr(skillCfg.row.fightAttrStr));
				}
				//强化效果
				addEnhance(config, skillCfg.row);
			}
		}

		//实例化技能
		for (SkillCfg cfg : allSkrList) {
			Skill skill = config.skill.buildById(owner, cfg.id);
			if (skill != null) {
				if (cfg.row.type == GDSkill.Type.PASSIVE) {
					passive.add(skill);
					if(skill.passive instanceof 英雄觉醒PH){
						英雄觉醒ph = (英雄觉醒PH)skill.passive;
					}
				} else {
					active.add(skill);
				}
				//读取被动脚本
				if (skill.passive != null) {
					handlers.add(skill.passive);
				}
			}
		}
	}

    //强化效果列表
	private Set<SkillEnhanceRow> enhanceRows = new HashSet<>();

	//添加强化效果
	private void addEnhance(AllPlayCfg config, SkillBaseRow row) {
		if (XT.isBlank(row.enhanceList)) {
			return;
		}
		for (Integer enhanceTid : row.enhanceList) {
			SkillEnhanceCfg enhanceCfg = config.enhance.get(enhanceTid);
			if (enhanceCfg != null) {
				enhanceRows.add(enhanceCfg.row);
			}
		}
	}

	/**
	 * 获取技能强化效果配置
	 * @param baseRow
	 * @return
	 */
	public List<SkillEnhanceRow> getEnhance(SkillBaseRow baseRow) {
		List<SkillEnhanceRow> result = new ArrayList<>();
		for (SkillEnhanceRow enhanceRow : enhanceRows) {
			if (enhanceRow.targetType != null && enhanceRow.targetType != baseRow.type) {
				continue;
			}
			if (XT.isNotBlank(enhanceRow.tarSkills) && !enhanceRow.tarSkills.contains(baseRow.id)) {
				continue;
			}
			if (XT.isNotBlank(enhanceRow.tarTags) && !ListKit.hasIntersection(enhanceRow.tarTags, baseRow.tags)) {
				continue;
			}
			if (XT.isNotBlank(enhanceRow.tarEffectTypes) && !enhanceRow.tarEffectTypes.contains(baseRow.effectType)) {
				continue;
			}
			result.add(enhanceRow);
		}
		return result;
	}


	private List<PassiveHandler> handlers = new ArrayList<>();

	@JsonIgnore
	public List<PassiveHandler> getHandlers() {
		return handlers;
	}

	public void forHandlers(Consumer<PassiveHandler> consumer) {
		for (PassiveHandler handler : handlers) {
			consumer.accept(handler);
		}
	}

	public <T extends PassiveHandler> T getHandler(Class<T> clazz) {
		for (PassiveHandler handler : handlers) {
			if (handler.getClass() == clazz) {
				return (T) handler;
			}
		}
		return null;
	}

	public boolean containTag(String tag) {
		if (StringUtils.isBlank(tag)) {
			return false;
		}
		for (Skill skill : getAllSkill()) {
			if (skill.cfg.containTag(tag)) {
				return true;
			}
		}
		return false;
	}

	public boolean containTag(List<String> tags) {
		for (Skill skill : getAllSkill()) {
			if (skill.cfg.containTags(tags)) {
				return true;
			}
		}
		return false;
	}

	public Skill getActiveSkillByProtoId(int protoId) {
		for (Skill skill : active) {
			if (skill.cfg.row.protoId == protoId) {
				return skill;
			}
		}
		return null;
	}

	private Set<Integer> filterSkill(AllPlayCfg playCfg, Set<Integer> skrList) {
		Map<Integer, SkillBaseRow> noRepeatSkr = new HashMap<>();
		for (Integer skr : skrList) {
			SkillCfg skillCfg = playCfg.skill.get(skr);
			if (skillCfg == null) {
				continue;
			}
			SkillBaseRow skillRow = skillCfg.row;
			SkillBaseRow before = noRepeatSkr.get(skillRow.protoId);
			if (before == null) {
				noRepeatSkr.put(skillRow.protoId, skillRow);
			} else {
				if (skillRow.level > before.level) {
					noRepeatSkr.put(skillRow.protoId, skillRow);
				}
			}
		}
		return noRepeatSkr.values().stream().mapToInt(a -> a.tid).boxed().collect(Collectors.toSet());
	}

	public void addReplace(AllPlayCfg playCfg, SkillReplaceCfg cfg) {
		Skill replaceSkill = playCfg.skill.buildById(owner, cfg.replaceSkill);
		if (replaceSkill == null) {
			return;
		}
		boolean change = active.removeIf(cfg::needReplace);
		if (change) {
			active.add(replaceSkill);
		}
	}
	private 英雄觉醒PH 英雄觉醒ph;

	public boolean addAwakenEnergy(ActionCtx action, double value) {
		if (英雄觉醒ph != null) {
			英雄觉醒ph.addEnergy(action, value);
			return true;
		}else {
			return false;
		}
	}

	public void doAwaken(ActionCtx action, int assignRound) {
		if (英雄觉醒ph != null) {
			英雄觉醒ph.doAwaken(action, assignRound);
		}
	}

	public double getEnergy() {
		if (英雄觉醒ph != null) {
			return 英雄觉醒ph.getCurValue();
		} else {
			return -1;
		}
	}
}
